
#include <BBuffer>
#include "member_BBuffer.h"

using namespace BWE;

#define member					(*(member_BBuffer*)_ptr)
#define member_allocate()		_ptr = new member_BBuffer(this)
#define member_release()		delete (member_BBuffer*)_ptr

BBuffer::BBuffer(int size)
{
	member_allocate();
	member.bytes.resize(size);
}
BBuffer::BBuffer(const BByte* bytes, int size)
{
	member_allocate();
	member.bytes.append(bytes, size);
}
BBuffer::BBuffer(const BByteArray& bytes)
{
	member_allocate();
	member.bytes = bytes;
}
BBuffer::BBuffer(const BBuffer& other)
{
	member_allocate();
	member.bytes = buffer_member(&other)->bytes;
}
BBuffer::BBuffer(const BString& str)
{
	member_allocate();
	if (str.size())
	{
		if (this->mode() & IO_Text)
			member.bytes.append((const BByte*)str.cstr(), str.size());
		else
			member.bytes.append((const BByte*)str.cstr(), str.size() + 1);
	}
}
BBuffer::BBuffer(const char* cstr)
{
	member_allocate();
	if (cstr)
	{
		int len = (int)strlen(cstr);
		if (this->mode() & IO_Text)
			member.bytes.append((const BByte*)cstr, len);
		else
			member.bytes.append((const BByte*)cstr, len + 1);
	}
}
BBuffer::~BBuffer()
{
	member_release();
}

void BBuffer::setMode(IOMode mode)
{
	if (member.mode != mode)
	{
		member.mode = mode;
	}
}
IOMode BBuffer::mode() const
{
	return member.mode;
}

bool BBuffer::reset(const BByte* bytes, int size)
{
	if (member.bytes.data() != bytes)
	{
		member.bytes.reset();
		member.bytes.append(bytes, size);
		member.offset = 0;
		return true;
	}
	return false;
}
bool BBuffer::reset(const BByteArray& bytes)
{
	if (&(member.bytes) != &bytes)
	{
		member.bytes = bytes;
		member.offset = 0;
		return true;
	}
	return false;
}
bool BBuffer::reset(const BBuffer& buffer)
{
	if (this != &buffer)
	{
		member.mode = buffer.mode();
		member.bytes = buffer.bytes();
		member.offset = 0;
		return true;
	}
	return false;
}
bool BBuffer::reset(const BString& str)
{
	member.bytes.clear();
	if (str.size())
	{
		if (this->mode() & IO_Text)
			member.bytes.append((const BByte*)str.cstr(), str.size());
		else
			member.bytes.append((const BByte*)str.cstr(), str.size() + 1);
	}
	member.offset = 0;
	return true;
}
bool BBuffer::reset(const char* cstr)
{
	member.bytes.clear();
	if (cstr)
	{
		int len = (int)strlen(cstr);
		if (this->mode() & IO_Text)
			member.bytes.append((const BByte*)cstr, len);
		else
			member.bytes.append((const BByte*)cstr, len + 1);
	}
	member.offset = 0;
	return true;
}

bool BBuffer::insert(const BByte* bytes, int size)
{
	if (member.offset > member.bytes.size())
		return false;
	if (member.offset == member.bytes.size())
		member.bytes.append(bytes, size);
	else
		member.bytes.insert(member.offset, bytes, size);
	member.offset += size;
	return true;
}
bool BBuffer::insert(const BByteArray& bytes)
{
	int size = bytes.size();
	if (member.offset > member.bytes.size())
		return false;
	if (member.offset == member.bytes.size())
		member.bytes.append(bytes, 0, size);
	else
		member.bytes.insert(member.offset, bytes, size);
	member.offset += size;
	return true;
}
bool BBuffer::insert(const BBuffer& buffer)
{
	int size = buffer.size();
	if (member.offset > member.bytes.size())
		return false;
	if (member.offset == member.bytes.size())
		member.bytes.append(buffer.bytes(), size);
	else
		member.bytes.insert(member.offset, buffer.bytes(), size);
	member.offset += size;
	return true;
}
bool BBuffer::insert(const BString& str)
{
	int size = str.size();
	if (member.mode & IO_Text)
		return write(str.cstr(), size);
	return write(str.cstr(), size + 1);
}
bool BBuffer::insert(const char* cstr)
{
	if (cstr == 0)
		return false;
	int size = (int)strlen(cstr);
	if (cstr[size] != 0)
		return false;
	if (member.mode & IO_Text)
		return write(cstr, size);
	return write(cstr, size + 1);
}

bool BBuffer::append(const BByte* bytes, int size)
{
	if (member.offset > member.bytes.size())
		return false;
	member.offset = member.bytes.size();
	member.bytes.append(bytes, size);
	member.offset += size;
	return true;
}
bool BBuffer::append(const BByteArray& bytes)
{
	int size = bytes.size();
	if (member.offset > member.bytes.size())
		return false;
	member.offset = member.bytes.size();
	member.bytes.append(bytes, 0, size);
	member.offset += size;
	return true;
}
bool BBuffer::append(const BBuffer& buffer)
{
	int size = buffer.size();
	if (member.offset > member.bytes.size())
		return false;
	member.offset = member.bytes.size();
	member.bytes.append(buffer.bytes(), size);
	member.offset += size;
	return true;
}
bool BBuffer::append(const BString& str)
{
	int size = str.size();
	member.offset = member.bytes.size();
	if (member.mode & IO_Text)
		return write(str.cstr(), size);
	return write(str.cstr(), size + 1);
}
bool BBuffer::append(const char* cstr)
{
	if (cstr == 0)
		return false;
	int size = (int)strlen(cstr);
	if (cstr[size] != 0)
		return false;
	member.offset = member.bytes.size();
	if (member.mode & IO_Text)
		return write(cstr, size);
	return write(cstr, size + 1);
}

const BByteArray& BBuffer::bytes() const
{
	return member.bytes;
}
BByteArray& BBuffer::bytes()
{
	return member.bytes;
}

BByte BBuffer::byte(int index) const
{
	return member.bytes(index);
}
const BByte* BBuffer::data() const
{
	return member.bytes.data();
}

bool BBuffer::seek(int offset) const
{
	if (offset < 0 || offset > member.bytes.size())
		return false;
	if (member.offset != offset)
	{
		member.offset = offset;
	}
	return true;
}
bool BBuffer::wseek(int offset)
{
	if (offset < 0)
		return false;
	if (offset > member.bytes.size())
		member.bytes.append((BByte)0, offset - member.bytes.size());
	member.offset = offset;
	return true;
}

bool BBuffer::empty() const
{
	return member.bytes.empty();
}
bool BBuffer::resize(int size)
{
	if (member.bytes.resize(size))
	{
		if (member.offset > size)
			member.offset = size;
		return true;
	}
	return false;
}
void BBuffer::reset(int size)
{
	member.bytes.reset(size);
	member.offset = size;
}
void BBuffer::reset()
{
	member.bytes.reset();
	member.offset = 0;
}
void BBuffer::clear()
{
	member.bytes.clear();
	member.offset = 0;
}

void BBuffer::remove(int size)
{
	member.bytes.remove(member.offset, size);
}

bool BBuffer::begin() const
{
	return member.offset == 0;
}
bool BBuffer::end() const
{
	return member.offset == member.bytes.size();
}

int BBuffer::size() const
{
	return member.bytes.size();
}
int BBuffer::offset() const
{
	return member.offset;
}

bool BBuffer::read(void* data, int size) const
{
	int offset = member.offset;
	if (member.offset + size > member.bytes.size())
		return false;
	memcpy(data, member.bytes.data() + member.offset, size);
	member.offset += size;
	return true;
}
bool BBuffer::write(const void* data, int size)
{
	if (member.offset > member.bytes.size())
		return false;
	if (member.offset == member.bytes.size())
	{
		member.bytes.append((const BByte*)data, size);
	}
	else
	{
		member.bytes.expand(member.offset + size - member.bytes.size());
		memcpy(member.bytes.data() + member.offset, data, size);
	}
	member.offset += size;
	return true;
}

bool BBuffer::read(BString& text) const
{
	text.reset();
	while (1)
	{
		char c = 0;
		if (!read(c))
			break;
		text.append(c);
		if (c == 0)
			break;
	}
	return text.size();
}
bool BBuffer::write(const BString& text)
{
	if (member.mode & IO_Text)
		return write(text.cstr(), text.size());
	return write(text.cstr(), text.size() + 1);
}

bool BBuffer::readCStr(char* cstr, int size) const
{
	if (!cstr || size <= 0)
		return false;
	char code = 0;
	for (int i = 0; i < size; i++)
	{
		if (!read(code))
		{
			cstr[0] = 0;
			return false;
		}
		cstr[i] = code;
		if (code == 0)
		{
			return true;
		}
	}
	return false;
}
bool BBuffer::writeCStr(const char* cstr, int size)
{
	if (cstr == 0)
		return false;
	if (size < 0)
		size = (int)strlen(cstr);
	if (cstr[size] != 0)
		return false;
	return write(cstr, size + 1);
}

bool BBuffer::readLine(char* cstr, int size) const
{
	for (int i = 0; i < size; i++)
	{
		char c = 0;
		if (!read(&c, 1))
			return i > 0;
		cstr[i] = c;
		if (c == '\n')
			return i > 0;
	}
	return false;
}
bool BBuffer::writeLine(const char* cstr, int size)
{
	if (!cstr)
		return false;
	if (size == 0)
		return false;
	if (size < 0)
		size = (int)strlen(cstr);
	int count = 0;
	for (int i = 0; i < size; i++)
	{
		if (cstr[i] == '\n')
		{
			count = i + 1;
			break;
		}
	}
	if (count > 0)
	{
		if (!write(cstr, count))
			return false;
	}
	else
	{
		if (!write(cstr, size))
			return false;
		if (!write('\n'))
			return false;
	}
	return true;
}

bool BBuffer::readText(BString& text, int size) const
{
	if (size <= 0)
		return false;
	if (text.capacity() < size)
		text.reserve(size);
	text.reset();
	char* cstr = (char*)text.cstr();
	char code = 0;
	for (int i = 0; i < size; i++)
	{
		if (!read(code))
		{
			text.reset();
			return false;
		}
		cstr[i] = code;
		if (code == 0)
		{
			return true;
		}
	}
	return false;
}
bool BBuffer::writeText(const BString& text, int size)
{
	if (size < 0)
		size = text.size();
	return write(text.cstr(), size + 1);
}

bool BBuffer::readLine(BString& line) const
{
	line.reset();
	while (1)
	{
		char c = 0;
		if (!read(&c, 1))
			break;
		line.append(c);
		if (c == '\n')
			break;
	}
	return line.size();
}
bool BBuffer::writeLine(const BString& line)
{
	int count = line.find('\n');
	if (count > 0 && count < line.size())
	{
		count += 1;
		if (!write(line.cstr(), count))
			return false;
	}
	else
	{
		if (!write(line.cstr(), line.size()))
			return false;
		if (!write('\n'))
			return false;
	}
	return true;
}

const BBuffer& BBuffer::operator = (const BByteArray& bytes)
{
	reset(bytes);
	return *this;
}
const BBuffer& BBuffer::operator = (const BBuffer& buffer)
{
	reset(buffer);
	return *this;
}
const BBuffer& BBuffer::operator = (const BString& str)
{
	reset(str);
	return *this;
}
const BBuffer& BBuffer::operator = (const char* cstr)
{
	reset(cstr);
	return *this;
}
